#define __ALLNU__ true

#include	<types.h>
#include	<memory.h>
#include	<quickdraw.h>
#include	<toolutils.h>
#include	<fonts.h>
#include	<events.h>
#include	<windows.h>
#include	<dialogs.h>
#include	<menus.h>
#include	<desk.h>
#include	<textedit.h>
#include	<scrap.h>
#include	<Palette.h>
#include	<OSUtils.h>
#include	<segload.h>

extern _DataInit();

#define transparency 36

#define 	NotUSEBITMAP       	111 

/*
 * Resource ID constants.
 */
#define	appleID		128 			/* This is a resource ID */
#define	fileID 		129 			/* ditto */
#define	editID 		130 			/* ditto */

#define	appleMenu		0			/* MyMenus[] array indexes */
#define	aboutMeCommand	1

#define	fileMenu		1
#define	popCommand 	1
#define 	animate 		2
#define	quitCommand 	3

#define	editMenu		2
#define	undoCommand 	1
#define	cutCommand	3
#define	copyCommand 	4
#define	pasteCommand	5
#define	clearCommand	6

#define menuCount		 3
/*
 * For the one and only text window
 */
#define windowID		128
#define popupWinID		129
/*
 * For the About Sample... DLOG
 */
#define	aboutMeDLOG	128
#define	okButton		1
#define	authorItem	2			/* For SetIText */
#define	languageItem	3			/* For SetIText */

/*
 * C programs typically use macros for simple expressions which
 * must be function calls in Pascal.  Here are a couple of examples:
 */

/*
 * Inline SetRect() macro, efficient when (rectp) is a constant.
 * Must not be used if (rectp) has side effects.
 *
 * We could do an InsetRect() macro in a similar vein.
 */
#define SETRECT(rectp, _left, _top, _right, _bottom)	\
	(rectp)->left = (_left), (rectp)->top = (_top), 	\
	(rectp)->right = (_right), (rectp)->bottom = (_bottom)

/*
 * HIWORD and LOWORD macros, for readability.
 */
#define HIWORD(aLong)		(((aLong) >> 16) & 0xFFFF)
#define LOWORD(aLong)		((aLong) & 0xFFFF)

/*
 * Global Data objects, used by routines external to main().
 */
MenuHandle		MyMenus[menuCount]; 	/* The menu handles */
Boolean 		DoneFlag;				/* Becomes TRUE when File/Quit chosen */
TEHandle		TextH;					/* The TextEdit handle */

WindowPtr			S_PopupWin;
WindowPtr			myWindow;
PixMapHandle	S_savedPixHdl;
PicHandle		myPict;

#ifdef USEBITMAP
GrafPort		myCGrafPort;
GrafPtr   	myCGrafPtr; 
#else
CGrafPort		myCGrafPort;
CGrafPtr		myCGrafPtr;
#endif
int 		oldSeed;   

Boolean 		Animating = false;
WindowRecord	wRecord;


char message[] = "Foo";

pascal void Debugger() extern 0xA9FF;

pascal OSErr BitMapRgn(region, bMap)
BitMap* bMap;
RgnHandle region;
extern;

pascal Boolean Search(rgb,pos)

RGBColor* rgb;
int* pos;

{
RGBColor 	myRGB;
int 	i,result,ctSize;
GDHandle  dev;

	dev = GetGDevice();
	ctSize = (*(*(*dev) -> gdPMap) -> pmTable) -> ctSize;
/*	Debugger(); */
	for (i = 0; i <= ctSize; i++)
   	  {
	    if (
	    (*(*(*dev) -> gdPMap) -> pmTable) -> ctTable[i].rgb.red == rgb -> red &&
	    (*(*(*dev) -> gdPMap) -> pmTable) -> ctTable[i].rgb.green == rgb -> green &&
	    (*(*(*dev) -> gdPMap) -> pmTable) -> ctTable[i].rgb.blue == rgb -> blue  )
	      {
		*pos = i;
		return(true);
	      }
	  }
}

/****************************************************************/
/* draws whatever using animating entries so we can change them later */
void   DrawSomeStuff ()
 
{
Rect myRect;
RgnHandle myReg;
int	i;
PixMap    temp;
Rect	tempRect;
Rect	falseRect;
OSErr	err;
PolyHandle myPoly;
Pattern 	myPat;

SetRect(&falseRect, 0, 0, 50, 50);

#ifdef USEBITMAP
EraseRect(&(myCGrafPtr->portBits.bounds));
#else
EraseRect(&((*(myCGrafPtr->portPixMap))->bounds)); 
#endif				  	  
  SetRect(&myRect,10,10,150,150);
	PmForeColor(2);
	PaintRect(&myRect);
	myReg = NewRgn();
	OpenRgn();
	  SetRect(&myRect,80,10,350,150);
	  FrameOval(&myRect);
	CloseRgn(myReg);
	PmForeColor(3);
	PaintRgn(myReg);
	DisposeRgn(myReg);


/*	myReg = NewRgn();
	OpenRgn();
	  MoveTo(50,5);
	  LineTo(70,20);
	  LineTo(40,20);
	  LineTo(50,5);
	CloseRgn(myReg);

	PmForeColor(5);
	FrameRgn(myReg);

	PmForeColor(6);
	FillRgn(myReg, qd.black); 

	DisposeRgn(myReg);
*/	
  SetRect(&myRect,0,0,50,50);
  
  
	myPict = OpenPicture(&myRect);
	myPoly = OpenPoly();  
	  MoveTo(50,5);
	  LineTo(70,20);
	  LineTo(40,20);
	  LineTo(50,5);
	ClosePoly();
	
	PmForeColor(6);
	FramePoly(myPoly);
	PmForeColor(5);
	FillPoly(myPoly, qd.black);
	MoveTo(40,30);
	DrawString(message);

	ClosePicture();
	
	DrawPicture(myPict,&myRect); 
	
	PenSize(5,5);
  	PmForeColor(4);
	MoveTo(20,250);
	LineTo(400,300);

/* This code is here not to create more mess but to exemplify a bug in QD that inverts
the pattern being used when drawing using transparency mode and painting roundrects or ovals */

	PenMode(transparency+patCopy);  /* transparency is the cause of problems */
	
/* Lets put things back to default */
 	PmForeColor(1);
	PmBackColor(0);
	
	
	GetIndPattern(myPat, 0, 35);
	PenPat(myPat);
	
	SetRect(&myRect,150,150,250,250);
	PaintRect(&myRect);

	SetRect(&myRect,250,250,350,350);
/* 	PaintRoundRect(&myRect,20,20);   This also causes the pattern to invert */

	PaintOval(&myRect);

	}


Rect pixRect = {0,0,1224,427};

void MakeUsePort()
{
   int 		rowBytes;
   Size		sizeBits;
   GDHandle	theDevice;
   short		theDepth;
   CTabHandle	cTabHdl;
   ColorSpec	*cSpec;
   CGrafPtr	oldPort;
   Ptr		temp;
   PolyHandle myPoly;
   Rect myRect,frameRect;
   
   SetRect(&myRect,0,0,1224,427);
   GetPort(&oldPort);
#ifdef USEBITMAP

   rowBytes = (1 * ( pixRect.right - 
	                  pixRect.left + 15) / 16) * 2;
   myCGrafPtr->portBits.rowBytes = rowBytes;
   myCGrafPtr->portBits.bounds = pixRect;
   myCGrafPtr->portBits.baseAddr = (Ptr) NewPtr((pixRect.bottom - 
	             pixRect.top) * rowBytes);
   SetPort(myCGrafPtr);
   ClipRect(&myRect);
   EraseRect(&(myCGrafPtr->portRect));

	myPict = OpenPicture(&pixRect);
/* 	
	myPoly = OpenPoly();  
	  MoveTo(50,10);
	  LineTo(70,25);
	  LineTo(40,25);
	  LineTo(50,10);
	ClosePoly();
	
	ForeColor(redColor);
	
	FramePoly(myPoly); 

	ForeColor(cyanColor);
	
	FillPoly(myPoly, qd.black);
*/

	FrameArc(&frameRect,89,2);
	
	ClosePicture(); 
	
	DrawPicture(myPict,&pixRect);
	
	KillPoly(myPoly);
#else
   theDevice = (GDHandle) GetGDevice();
   theDepth =  (*(*theDevice)->gdPMap)->pixelSize; 

   rowBytes = (theDepth * ( (*((CGrafPtr) myWindow) ->portPixMap)->bounds.right - 
	                         (*((CGrafPtr) myWindow) ->portPixMap)->bounds.left + 15) / 16) * 2;
   sizeBits = ((*((CGrafPtr) myWindow) ->portPixMap)->bounds.bottom - 
	             (*((CGrafPtr) myWindow) ->portPixMap)->bounds.top) * rowBytes;


   temp = (Ptr) NewPtr (sizeBits);
   (*(myCGrafPtr->portPixMap))->baseAddr = temp;
   (*(myCGrafPtr->portPixMap))->rowBytes = rowBytes  + 0x8000; 
   (*(myCGrafPtr->portPixMap))->bounds = (*((CGrafPtr) myWindow) ->portPixMap)->bounds; 
   (*(myCGrafPtr->portPixMap))->pixelSize = theDepth; 
 
   SetPort(myCGrafPtr);

   ClipRect(&((*(myCGrafPtr->portPixMap))->bounds));

   SetPalette(myCGrafPtr, GetPalette(myWindow), 0xc0);  /* use new constants ****** */
   
   oldSeed = (*(*(myCGrafPtr->portPixMap))->pmTable)->ctSeed;

   DrawSomeStuff();
#endif   
   
   SetPort(oldPort);
 
   }
/****************************************************************/
/* used to clober the stuff in the source window */
void   DrawPopupWindow (popRect, theWin)
 
Rect   		*popRect;		/* pop-up rect in theWin local coord */
WindowPtr		theWin; 		/* current grafport */
{
 
   /*---- show pop-up window ----
   ShowHide (S_PopupWin, true);*/
/*	 BringToFront(S_PopupWin); */
   SendBehind (myWindow, S_PopupWin);
	 SetPort (S_PopupWin);
}

/**************************************************************/
void   closePopup  ()
 
{
 
/*   ShowHide (S_PopupWin, false);    hide pop-up window */
   SendBehind (S_PopupWin, NULL);
 
   SetPort(myWindow);
}
 
/****************************************************************/
void   DoPopup ()

{
Rect	aRect;
Point	aPt;
RGBColor	myColor;


	DrawPopupWindow (&aRect, myWindow);
	do {
	} while (!Button());
	closePopup (myWindow);
	
	SetPort (myWindow);
	ValidRect (&aRect);
}

/**************************************************************/

int main()
{
	Rect				screenRect;
	Rect				dragRect;
	Rect				txRect;
	Point				mousePt;
	CursHandle			ibeamHdl;
	EventRecord 			myEvent;
	WindowPtr				theActiveWindow;
	WindowPtr				whichWindow;
	extern void 			setupMenus();
	extern void 			doCommand();
	Boolean 				first = true;
	GDHandle				saveDev,currDev,activeDev[6];
	pascal Boolean (*Func)(*x,*y);
	int 				devs,i;

/* Initialize function pointer, there has to be a better way to do this */
Func = Search;
	

	/*
	 * Initialization traps
	 */
	UnloadSeg(_DataInit);
	InitGraf(&qd.thePort);
	InitFonts();
	FlushEvents(everyEvent, 0);
	InitWindows();
	InitMenus();
	TEInit();
	InitDialogs(nil);
	InitCursor();
	/*
	 * setupMenus is execute-once code, so we can unload it now.
	 */
	setupMenus();			/* Local procedure, below */
	UnloadSeg(setupMenus);

	screenRect = qd.screenBits.bounds;
	SETRECT(&dragRect, 4, 20 + 4, screenRect.right-4, screenRect.bottom-4);

	myWindow = GetNewCWindow(windowID, &wRecord, (WindowPtr) -1);
	S_PopupWin = GetNewCWindow(popupWinID, nil, myWindow);
	SetPort(myWindow);
	
/* Lets open a grafport once and for all hereafter we'll just init it accordingly
   if needed
*/
myCGrafPtr = &myCGrafPort;
#ifdef USEBITMAP
OpenPort(myCGrafPtr);	
#else
OpenCPort(myCGrafPtr); 
#endif


	MakeUsePort();	/* create offscreen stuff */

/* ***************************************************** */
/* Initialize device handles array to do the search proc 
   adding stuff when an activate event occurs
*/
devs = 0;
currDev = GetDeviceList();

do 
  {
    if (currDev != GetMainDevice())
      {
        activeDev[devs] = currDev;
        devs++;
      }
  }
while (currDev = GetNextDevice(currDev));
	 
	DoneFlag = false;
	for ( ;; ) {
	          if (Animating)
		  GoAnimate();
		if (DoneFlag) {
			/*
			 * Quit has been requested, by the File/Quit menu, or perhaps
			 * by a fatal error somewhere else (missing resource, etc).
			 * Here we could put up a Save Changes? DLOG, which would also
			 * allow the Cancel buttion to set DoneFlag to false.
			 */
			break;		/* from main event loop */
		}
		/*
		 * Main Event tasks:
		 */
		SystemTask();
		theActiveWindow = FrontWindow();		/* Used often, avoid repeated calls */
		/*
		 * Handle the next event.
		 * In a more complex application, this switch statement
		 * would probably call satellite routines to handle the
		 * major cases (mouseDown, keyDown, etc), but our actions
		 * are simple here and it suffices to perform the code in-line.
		 */
		if (!GetNextEvent(everyEvent, &myEvent)) {
			/*
			 * A null or system event, not for me.
			 * Here is a good place for heap cleanup and/or
			 * segment unloading if I want to.
			 */
			continue;
		}
		/*
		 * In the unlikely case that the active desk accessory does not
		 * handle mouseDown, keyDown, or other events, GetNextEvent() will
		 * give them to us!  So before we perform actions on some events,
		 * we check to see that the affected window in question is really
		 * our window.
		 */
		switch (myEvent.what) {
			case mouseDown:
				switch (FindWindow(&myEvent.where, &whichWindow)) {
					case inSysWindow:
						SystemClick(&myEvent, whichWindow);
						break;

					case inMenuBar:
						doCommand(MenuSelect(&myEvent.where));
						break;

					case inDrag:
						DragWindow(whichWindow, &myEvent.where, &dragRect);
						break;

					case inGrow:
						/* There is no grow box. (Fall through) */

					case inContent:
						if (whichWindow != theActiveWindow) {
							SelectWindow(whichWindow);
						}
						break;

					default:
						break;
				}/*endsw FindWindow*/
				break;

			case keyDown:
			case autoKey:
				if (myWindow == theActiveWindow) {
					if (myEvent.modifiers & cmdKey) {
						doCommand(MenuKey(myEvent.message & charCodeMask));
					}
				}
				break;

			case activateEvt:
				break;

			case updateEvt:
				if ((WindowPtr) myEvent.message == myWindow) 
				{
				  SetPort(myWindow);
#ifndef USEBITMAP
				  if ( oldSeed != 
				        (*(*(myCGrafPtr->portPixMap))->pmTable)->ctSeed)
				    {
				      DisposPtr((*(myCGrafPtr->portPixMap))->baseAddr);
				      MakeUsePort(); /* again create offscreen stuff */
				    }
#endif
				  BeginUpdate(myWindow);
				  
				  
				  saveDev = GetGDevice();
				  for (i = 0; i< devs; i++)
				    {
				      SetGDevice(activeDev[i]);
				      AddSearch(Func);
				    }
				    
				  SetGDevice(saveDev);
				  
#ifdef USEBITMAP
				  CopyBits (&(myCGrafPtr->portBits), 
				            &(myWindow ->portBits), 
				  	  &(myCGrafPtr->portBits.bounds), 
				  	  &(myCGrafPtr->portBits.bounds), 
						0, NULL); 
#else				  
				  CopyBits (*(myCGrafPtr->portPixMap), 
				            &(myWindow ->portBits), 
				  	  &((*(myCGrafPtr->portPixMap))->bounds), 
				  	  &((*(myCGrafPtr->portPixMap))->bounds), 
						0, NULL); 
#endif
				  EndUpdate(myWindow);
				  
				  for (i = 0; i< devs; i++)
				    {
				      SetGDevice(activeDev[i]);
				      DelSearch(Func);
				    }
				  SetGDevice(saveDev);
				  }
				break;

			default:
				break;

		}/*endsw myEvent.what*/
	}/*endfor Main Event loop*/
/* This calls need to be here to make sure the animated entries are un-reserved */
	CloseWindow(myWindow);
	DisposeWindow(S_PopupWin);
	return 0;		/* Return from main() to allow C runtime cleanup */
}

/*
 * Demonstration of the segmenting facility:
 *
 * This code is execute-once, so we toss it in the "Initialize"
 * segment so that main() can unload it after it's called.
 *
 * There really isn't much here, but it demonstrates the segmenting facility.
 */
/*
 * Set the segment to Initialize.  BEWARE: leading and trailing white space
 * would be part of the segment name!
 */
#define	__SEG__ Initialize

/*
 * Set up the Apple, File, and Edit menus.
 * If the MENU resources are missing, we die.
 */
void setupMenus()
{
	extern		MenuHandle	MyMenus[];
	register	MenuHandle	*pMenu;

	/*
	 * Set up the desk accessories menu.
	 * The "About Sample..." item, followed by a grey line,
	 * is presumed to be already in the resource.  We then
	 * append the desk accessory names from the 'DRVR' resources.
	 */
	MyMenus[appleMenu] = GetMenu(appleID);
	AddResMenu(MyMenus[appleMenu], (ResType) 'DRVR');
	/*
	 * Now the File and Edit menus.
	 */
	MyMenus[fileMenu] = GetMenu(fileID);
	MyMenus[editMenu] = GetMenu(editID);
	/*
	 * Now insert all of the application menus in the menu bar.
	 *
	 * "Real" C programmers never use array indexes
	 * unless they're constants :-)
	 */
	for (pMenu = &MyMenus[0]; pMenu < &MyMenus[menuCount]; ++pMenu) {
		InsertMenu(*pMenu, 0);
	}

	DrawMenuBar();

	return;
}

/*
 * Back to the Main segment.
 */
#define	__SEG__ Main

/*
 * Display the Sample Application dialog.
 * We insert two static text items in the DLOG:
 *		The author name
 *		The source language
 * Then wait until the OK button is clicked before returning.
 */
void showAboutMeDialog()
{
	GrafPtr 	savePort;
	DialogPtr	theDialog;
	short		itemType;
	Handle		itemHdl;
	Rect		itemRect;
	short		itemHit;

	GetPort(&savePort);
	theDialog = GetNewDialog(aboutMeDLOG, nil, (WindowPtr) -1);
	SetPort(theDialog);

	GetDItem(theDialog, authorItem, &itemType, &itemHdl, &itemRect);
	SetIText(itemHdl, "Flash Bazbo");
	GetDItem(theDialog, languageItem, &itemType, &itemHdl, &itemRect);
	SetIText(itemHdl, "C");

	do {
		ModalDialog(nil, &itemHit);
	} while (itemHit != okButton);

	CloseDialog(theDialog);

	SetPort(savePort);
	return;
}
/*
 * Process mouse clicks in menu bar
 */
void doCommand(mResult)
	long	mResult;
{
	int 		theMenu, theItem;
	char		daName[256];
	GrafPtr 		savePort;
	extern MenuHandle	MyMenus[];
	extern Boolean	DoneFlag;
	extern TEHandle 	TextH;
	extern void 	showAboutMeDialog();

	theItem = LOWORD(mResult);
	theMenu = HIWORD(mResult);		/* This is the resource ID */

	switch (theMenu) {
		case appleID:
			if (theItem == aboutMeCommand) {
				showAboutMeDialog();
			} else {
				GetItem(MyMenus[appleMenu], theItem, daName);
				GetPort(&savePort);
				(void) OpenDeskAcc(daName);
				SetPort(savePort);
			}
			break;

		case fileID:
			switch (theItem) {
				case popCommand:
				  DoPopup();
					break;
				case animate:
					Animating = !Animating;
					CheckItem(MyMenus[fileMenu], theItem, Animating);
					break;
			  	case quitCommand:
					DoneFlag = true;			/* Request exit */
					break;
				default:
					break;
			}
			break;

		case editID:
			/*
			 * If this is for a 'standard' edit item,
			 * run it through SystemEdit first.
			 * SystemEdit will return FALSE if it's not a system window.
			 */
			if ((theItem <= clearCommand) && SystemEdit(theItem-1)) {
				break;
			}
			switch (theItem) {
				case undoCommand:
				case cutCommand:
				  DoCut();
				case copyCommand:
				case pasteCommand:
				case clearCommand:
				default:
					break;
			} /*endsw theItem*/
			break;

		default:
			break;

	}/*endsw theMenu*/

	HiliteMenu(0);

	return;
}

/* ********************************************************** */
/* Changes the colors for the animated entries, big deal */

GoAnimate()
{
int i;
RGBColor colorVar;
PaletteHandle p;

	p = GetPalette(myWindow);
	for (i=2;i<5;i++)
	  {
	     GetEntryColor(p,i,&colorVar);
	     colorVar.red += Random();
	     colorVar.green += Random();
	     colorVar.blue += Random();
/*	     AnimateEntry(myWindow,i,&colorVar); */
	     AnimateEntry(myCGrafPtr,i,&colorVar);
	  } 
}

DoCut()
{
long length;

 
length = GetHandleSize((Handle)myPict);
  
  if  (!(ZeroScrap())) 
    {
      HLock((Handle) myPict);
      if ( PutScrap(length,'PICT',  *myPict) ) 
        Debugger();
    }
    
  else
    Debugger();
}
